using System;
using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    /**
     * An instruction that sets a property of the template rendering
     * environment.
     */
    public sealed class PropertySetting : TemplateElement // NOTE: Was internal
    {
        private readonly string _key;
        private readonly Expression _value;

        internal PropertySetting(string key, Expression value)
        {
            _key = key;
            _value = value;
        }

        internal override void SetLocation(
            Template.Template template, int beginColumn, int beginLine, int endColumn, int endLine)
        {
            base.SetLocation(template, beginColumn, beginLine, endColumn, endLine);
            if (!_key.Equals(Configurable.LocaleKey) &&
                !_key.Equals(Configurable.NumberFormatKey) &&
                !_key.Equals(Configurable.TimeFormatKey) &&
                !_key.Equals(Configurable.DateFormatKey) &&
                !_key.Equals(Configurable.DatetimeFormatKey) &&
                !_key.Equals(Configurable.TimeZoneKey) &&
                !_key.Equals(Configurable.BooleanFormatKey) &&
                !_key.Equals(Configurable.ClassicCompatibleKey) &&
                !_key.Equals(Configurable.UrlEscapingCharsetKey))
            {
                throw new ParseException(
                    "Error " + GetStartLocation()
                    + "\nInvalid setting name, or it is not allowed to change "
                    + "the value of the setting with FTL: "
                    + _key,
                    beginLine, beginColumn);
            }
        }

        internal override void Accept(Environment env)
        {
            ITemplateModel mval = _value.GetAsTemplateModel(env);
            string strval;
            if (mval is ITemplateScalarModel)
            {
                strval = ((ITemplateScalarModel) mval).GetAsString();
            }
            else if (mval is ITemplateBooleanModel)
            {
                strval = ((ITemplateBooleanModel) mval).GetAsBoolean() ? "true" : "false";
            }
            else if (mval is ITemplateNumberModel)
            {
                strval = ((ITemplateNumberModel) mval).GetAsNumber().ToString();
            }
            else
            {
                strval = _value.GetStringValue(env);
            }
            env.SetSetting(_key, strval);
        }

        public override string GetCanonicalForm()
        {
            return "<#setting " + _key + "=" + _value.GetCanonicalForm() + "/>";
        }

        public override string GetDescription()
        {
            return "setting " + _key + " set to " + "\"" + _value + "\" "
                   + "[" + GetStartLocation() + "]";
        }
    }
}